package com.qf.controller;

import com.fasterxml.jackson.core.JsonToken;
import com.sun.org.apache.regexp.internal.RE;
import org.redisson.RedissonMultiLock;
import org.redisson.api.*;
import org.redisson.client.RedisClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

@RestController
public class RedissonController {

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @GetMapping("/testJUCLock")
    public synchronized void testJUCLock() {

        synchronized (this) {

        }

        // 1.获取锁
        Lock jucLokc = new ReentrantLock();
        try {
            // 2.加锁
//            jucLokc.lock(); // 获取不到锁会一直阻塞

            // 获取不到锁后制定等待的时间，这个方法是有返回值的
            boolean b = jucLokc.tryLock(2000, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 3.释放锁
            jucLokc.unlock();
        }
    }

    @GetMapping("/test")
    public String test() throws InterruptedException {


        // 1.获取锁 hash test-lock uuid:线程id：1
        RLock lock = redissonClient.getLock("test-lock");

        try {
            // 2.加锁
            lock.lock(); // 获取不到锁就阻塞
            boolean b = lock.tryLock(2000, TimeUnit.SECONDS);

            // 3.处理义务
            Thread.sleep(1000 * 50);
            System.out.println("正在处理义务:" + Thread.currentThread().getId());

            return "ok";
        } finally {
            // 3.释放锁
            lock.unlock();
        }
    }

    @RequestMapping("/hello")
    public String hello() throws Exception {

        // 1.获取一把锁
        RLock lock = redissonClient.getLock("redis-lock");
        System.out.println("获取锁成功:" + Thread.currentThread().getName());

        // 2.加锁
//        lock.lock(); // 阻塞方法，获取不到锁会一直等待,默认是30s
        // 设置等待的时间为2s，2s后如果还是获取不到锁就返回false，锁超时时间还是30s
        boolean b = lock.tryLock(2, TimeUnit.SECONDS);

        // 用户自定义的锁的超时时间，设置等待的时间
        boolean b1 = lock.tryLock(2, 10, TimeUnit.SECONDS);

        if (b1) {
            System.out.println("加锁成功:" + Thread.currentThread().getName());

            // 3.执行业务代码
            try {
                System.out.println("执行业务代码:" + Thread.currentThread().getName());
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally { // 不管业务代码是否出现异常都要释放锁，所以释放锁的需要放在finally中
                // 4.释放锁
                lock.unlock();
                System.out.println("释放锁成功代码:" + Thread.currentThread().getName());
            }
            return "hello";
        } else {
            System.out.println("加锁失败:" + Thread.currentThread().getName());
            return "ok";
        }


    }

    @RequestMapping("/write")
    public String write() throws InterruptedException {
        System.out.println("进入写:" + Thread.currentThread().getId());
        // 获取插入redis的业务数据
        String str = System.currentTimeMillis() + "";

        // 获取读写锁
        RReadWriteLock rwlock = redissonClient.getReadWriteLock("anyRWLock");

        RLock rLock = rwlock.writeLock();  // 获取锁
        rLock.lock();         // 加锁

        System.out.println("写锁成功:" + Thread.currentThread().getId());
        try {
            // 模拟写入时间
            Thread.sleep(10000);
        } finally {
            rLock.unlock();
            System.out.println("写锁释放:" + Thread.currentThread().getId());
        }
        return str;
    }

    @RequestMapping("/read")
    public String read() {
        System.out.println("进入读");
        // 获取读写锁
        RReadWriteLock rwlock = redissonClient.getReadWriteLock("anyRWLock");

        // 获取读锁
        RLock rLock = rwlock.readLock();
        rLock.lock();     // 加读锁
        System.out.println("读锁成功:" + Thread.currentThread().getId());
        try {
            // 模拟读取数据需要10s
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            rLock.unlock(); // 释放读锁
        }
        return System.currentTimeMillis() + "";
    }


    @RequestMapping("/consumer")
    @ResponseBody
    public String consumer() throws InterruptedException {
        RSemaphore semaphore = redissonClient.getSemaphore("semaphore");
//        semaphore.tryAcquireAsync();
//        semaphore.tryAcquire(2);
//        boolean b1 = semaphore.tryAcquire(2, TimeUnit.SECONDS);
//        boolean b = semaphore.tryAcquire(2, TimeUnit.SECONDS); // -2
        boolean b = semaphore.tryAcquire(2); // 一次取两个，不够就直接返回
        boolean b1 = semaphore.tryAcquire(2, 2, TimeUnit.SECONDS); // 一次取两个，不够就等待2s
        System.out.println(b);
        return "consumer:";
    }

    @RequestMapping("/production")
    @ResponseBody
    public String production() {
        RSemaphore semaphore = redissonClient.getSemaphore("semaphore");
        semaphore.release(); // +1
        return "consumer";
    }


    @RequestMapping("/init")
    public String init() {
        // 在其他线程或其他JVM里
        RCountDownLatch latch = redissonClient.getCountDownLatch("anyCountDownLatch");
        latch.countDown(); // 完成一个任务
        return "init";
    }

    @RequestMapping("/task")
    public String task() throws InterruptedException {
        RCountDownLatch latch = redissonClient.getCountDownLatch("anyCountDownLatch");
        latch.trySetCount(5); // 任务的数量
        latch.await(); // 如果任务没有执行完一直在这里等待
        return "task";
    }

    int i =0;
    @GetMapping("/incr")
    public void incr() {
        Long increment = stringRedisTemplate.opsForValue().increment("incr-demo");
        long id = Thread.currentThread().getId();
        i++;
        System.out.println(id+":" + increment+" --> "+i);
    }
}
